#include "usart_send.h"
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "lwrb.h"
#include "printf.h"

#define MIN(a, b) ((a) < (b) ? (a) : (b))

USART_SendType *usartSendHead_handle = NULL;  // 串口数据结构体链表头
static void USART_SendAttach(USART_SendType *this);
uint8_t queue_size = 0;
uint16_t buff_size = 0;

lwrb_t ringbuff;
uint8_t ringbuff_data[USART_RING_BUFF_SIZE];

#define PRINT_BUFFER_SIZE 256
static char print_buffer[PRINT_BUFFER_SIZE];

extern void USART_Enter_Critical(void);
extern void USART_Exit_Critical(void);
extern void USART_port_output(USART_SendType *this,uint8_t *data, uint16_t size);

/**
 * @brief 串口发送初始化
 * 
 * @param this 串口发送结构体
 * @param huart 串口句柄
 * @param txSize_Max 缓冲区大小
 */
void USART_SendInit(USART_SendType *this, void *huart)
{
    this->handle = huart;
    this->usart_tx_sta = USART_SEND_IDLE;
    this->head = NULL;
    this->tail = NULL;

    USART_SendAttach(this);
    // 初始化环形缓冲区, 只初始化一次
    if (lwrb_is_ready(&ringbuff) == 0)
    {
        lwrb_init(&ringbuff, ringbuff_data, USART_RING_BUFF_SIZE);
    }
}

static void USART_SendAttach(USART_SendType *this)
{
    USART_SendType *target = usartSendHead_handle;
    while (target)
    {
        if (target == this)
            return;
        target = target->next;
    }
    this->next = usartSendHead_handle;
    usartSendHead_handle = this;
}

/**
 * @brief 将串口发送数据加入发送队列
 * 
 * @param this 串口句柄
 * @param data 数据
 * @param size 数据大小
 * @return uint8_t* 返回malloc后的(在队列中的)数据指针, NULL表示失败
 */
uint8_t* USART_PushData(USART_SendType *this, uint8_t *data, uint16_t size, Usart_SendState *state, Usart_SendMode mode)
{
    // 检测是否超过队列最大长度
    if (queue_size >= USART_QUEUE_MAX_SIZE)
    {
        *state = USART_SEND_QUEUE_FULL;
        return NULL;
    }
    if (buff_size + size >= USART_BUFF_SIZE)
    {
        *state = USART_SEND_BUFF_FULL;
        return NULL;
    }

    USART_Enter_Critical(); // 关键区域
    DataQueue *newData = (DataQueue *)malloc(sizeof(DataQueue));    // 申请队列内存
    if (newData == NULL)
    {
        *state = USART_SEND_MALLOC_FAIL;
        USART_Exit_Critical();  // 退出关键区域
        return NULL;
    }

    if (mode == USART_USE_RING_BUFF)
    {
        if (lwrb_get_free(&ringbuff) < size)    // 检测环形缓冲区是否有足够的空间
        {
            *state = USART_SEND_BUFF_FULL;
            USART_Exit_Critical();  // 退出关键区域
            return NULL;
        }
        lwrb_write(&ringbuff, data, size);  // 将数据写入环形缓冲区
        newData->data = NULL;
        *state = USART_SEND_TO_RING_BUFF;
    }
    else if (mode == USART_USE_MOLLOC)
    {
        newData->data = (uint8_t *)malloc(size*sizeof(uint8_t));        // 申请数据内存
        if (newData->data == NULL)
        {
            *state = USART_SEND_MALLOC_FAIL;
            USART_Exit_Critical();  // 退出关键区域
            return NULL;
        }

        memcpy(newData->data, data, size);  // 拷贝数据, 保证数据有效
        buff_size += size;
        *state = USART_SEND_SUCCESS;
    }
    else
    {
        newData->data = data;
        *state = USART_SEND_SUCCESS;
    }

    
    newData->size = size;
    newData->mode = mode;
    newData->next = NULL;
    
    // 将数据加入队列中
    if (this->head == NULL)
    {
        this->head = newData;
        this->tail = newData;
    }
    else
    {
        this->tail->next = newData;
        this->tail = newData;
    }
    queue_size++;
    USART_Exit_Critical();  // 退出关键区域

    return newData->data;
}

/**
 * @brief 删除发送完成的数据和队列
 * 
 * @param this 指针
 */
void USART_PopData(USART_SendType *this)
{
    // 存在并发问题
    if (this->head->mode == USART_USE_RING_BUFF) {
        uint16_t read_length = lwrb_get_linear_block_read_length(&ringbuff);
        if (read_length < this->head->size) {   // 环形缓冲区是否还有数据未发送完
            lwrb_skip(&ringbuff, read_length); // 跳过已经发送完的数据
            this->head->size -= read_length;    // 更新数据大小
            return ;
        } else {
            lwrb_skip(&ringbuff, this->head->size); // 跳过已经发送完的数据
        }
    }

    if (this->head != NULL)
    {
        DataQueue *oldData = this->head;
        this->head = this->head->next;
        if (oldData->mode == USART_USE_MOLLOC) {
            free(oldData->data);
            buff_size -= oldData->size;
        }
        queue_size--;
        free(oldData);
    }
    // 如果队列为空, 尾指针也为空
    if (this->head == NULL)
    {
        this->tail = NULL;
    }
}

/**
 * @brief 串口发送数据
 * 
 * @param this 串口发送结构体
 * @param data 要发送的数据
 * @param size 数据大小
 */
Usart_SendState USART_SendData(USART_SendType *this, uint8_t *data, uint16_t size, Usart_SendMode mode)
{
    Usart_SendState state;
    if (this->usart_tx_sta == USART_SEND_IDLE)
    {
        this->usart_tx_sta = USART_SEND_BUSY;
        data = USART_PushData(this, data, size, &state, mode);    // 将数据加入队列
        if (data == NULL && state != USART_SEND_TO_RING_BUFF)  // 内存分配失败
        {
            this->usart_tx_sta = USART_SEND_IDLE;
            return state;  // 内存分配失败
        }
        if (state == USART_SEND_TO_RING_BUFF) {
            USART_port_output(this, lwrb_get_linear_block_read_address(&ringbuff), size); // 发送环形缓冲区的数据
        } else {
            USART_port_output(this, data, size); // 直接发送队列的数据
        }
    }
    else if (this->usart_tx_sta == USART_SEND_BUSY)
    {
        data = USART_PushData(this, data, size, &state, mode);    // 将数据加入队列
        if (data == NULL && state != USART_SEND_TO_RING_BUFF)  // 内存分配失败
        {
            return state;  // 内存分配失败
        }
    }
    return USART_SEND_SUCCESS;  // 发送成功
}

/**
 * @brief 串口发送数据
 * 
 * @param this 串口发送结构体
 * @param format 格式化字符串
 * @return Usart_SendState 发送状态
 */
Usart_SendState USART_Printf(USART_SendType *this, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    uint16_t size = vsnprintf(print_buffer, PRINT_BUFFER_SIZE, format, args);
    va_end(args);
    return USART_SendData(this, (uint8_t *)print_buffer, size, USART_USE_MOLLOC);
}

/**
 * @brief 串口发送完成回调函数
 * 
 * @param this 串口发送结构体
 */
void USART_SendCallback(void *handle)
{
    // 存在并发问题
    USART_SendType *this = usartSendHead_handle;
    while (this)
    {
        if (handle == this->handle)   // 找到对应的串口
        {
            USART_Enter_Critical(); // 进入临界区
            USART_PopData(this);    // 删除发送完成的数据
            if (this->head != NULL)
            {
                if (this->head->mode == USART_USE_RING_BUFF) {
                    uint16_t size = MIN(lwrb_get_linear_block_read_length(&ringbuff), this->head->size);
                    USART_port_output(this, lwrb_get_linear_block_read_address(&ringbuff), size); // 继续发送
                } else {
                    USART_port_output(this, this->head->data, this->head->size); // 继续发送
                }
            }
            else
            {
                this->usart_tx_sta = USART_SEND_IDLE;   // 转换为空闲状态
            }
            USART_Exit_Critical();  // 退出临界区
            return ;
        }
        this = this->next;
    }
}

